using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Security;
using System.Reflection;
using System.Globalization;

namespace Microsoft.Office.Project.EPMSync.Config.Library
{
    public class SyncConfigFile
    {
        private SyncConfig _syncConfig;
        private bool _syncFileRead;
        private string _syncFileName;
        private Tracing _tracing;

        #region Initialization

        public SyncConfigFile()
        {
            _syncFileName = "EPMSync.config";
            ReadConfigFromFile();
        }

        public SyncConfigFile(string syncConfigFileName)
        {
            _syncFileName = syncConfigFileName;
            ReadConfigFromFile();
        }

        public SyncConfigFile(Tracing tracePtr)
        {
            _syncFileName = "EPMSync.config";
            _tracing = tracePtr;
            ReadConfigFromFile();
        }

        public SyncConfigFile(Tracing tracePtr, string syncConfigFileName)
        {
            _syncFileName = syncConfigFileName;
            _tracing = tracePtr;
            ReadConfigFromFile();
        }
        #endregion

        #region Properties
        public SyncConfig SyncConfiguration
        {
            get
            {
                if (_syncFileRead)
                    return _syncConfig;
                else
                    return null;
            }
        }
        #endregion

        #region File I/O Commands

        private void ReadConfigFromFile()
        {
            FileStream fs = null;
            XmlReader reader = null;

            try
            {
                if (XMLSchemaVersionMatches)
                {
                    // Create an instance of the XmlSerializer specifying type and namespace.
                    XmlSerializer serializer = new XmlSerializer(typeof(SyncConfig));

                    // Verify the sync file exists.
                    FileInfo fi = new FileInfo(_syncFileName);
                    if (fi.Exists)
                    {
                        // A FileStream is needed to read the XML document.
                        fs = new FileStream(_syncFileName, FileMode.Open);
                        reader = new XmlTextReader(fs);

                        // Use the Deserialize method to restore the object's state.
                        _syncConfig = (SyncConfig)serializer.Deserialize(reader);

                        _syncFileRead = true;

                        if (_tracing != null)
                            _tracing.WriteTrace(_tracing.MainSwitch.TraceInfo, String.Format(CultureInfo.InvariantCulture, "Info: configuration file: {0},  was read sucessfully.", _syncFileName));
                    }
                    else
                    {
                        if (_tracing != null)
                            _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: configuration file: {0},  not found.", _syncFileName));
                        _syncFileRead = false;
                    }
                }
                else
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: The version of the SyncConfig assembly didn't match the version of the XML configuration file.");
                    _syncFileRead = false;
                }
            }
            catch (ArgumentOutOfRangeException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: FileMode invalid for the configuration file: {0}", _syncFileName));

                _syncFileRead = false;
            }
            catch (ArgumentNullException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: The configuration file  was null.");

                _syncFileRead = false;
            }
            catch (ArgumentException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file name: {0} was invalid.}", _syncFileName));

                _syncFileRead = false;
            }
            catch (SecurityException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The user doesn't hsve the required permissions of open the configuration file: {0}", _syncFileName));

                _syncFileRead = false;
            }
            catch (UnauthorizedAccessException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: Access to the configuration file: {0} was denied.", _syncFileName));

                _syncFileRead = false;
            }
            catch (PathTooLongException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0} path is too long {1}", _syncFileName, _syncFileName.Length));

                _syncFileRead = false;
            }
            catch (NotSupportedException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: There is a colon in the path name");

                _syncFileRead = false;
            }
            catch (FileNotFoundException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0},  was not found.", _syncFileName));

                _syncFileRead = false;
            }
            catch (DirectoryNotFoundException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file directory: {0},  was not found.", _syncFileName));

                _syncFileRead = false;
            }
            catch (InvalidOperationException ex)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An InvalidOpertionException occurred reading the configuration file: {0},  Expection: {1}", _syncFileName, ex.Message));

                _syncFileRead = false;
            }
            catch (IOException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An I/O error occurred in the configuration file: {0}", _syncFileName));

                _syncFileRead = false;
            }
            finally
            {
                if (reader != null)
                    reader.Close();

                if (fs != null)
                    fs.Close();

            }
        }



        public bool WriteConfigToFile()
        {
            bool completed = true;
            XmlSerializer serializer = new XmlSerializer(typeof(SyncConfig));
            FileStream fs = null;
            XmlWriter writer = null;

            try
            {
                // Determine whether the directory exists.
                FileInfo fi = new FileInfo(_syncFileName);
                if (!Directory.Exists(fi.DirectoryName))
                {
                    // Try to create the directory.
                    Directory.CreateDirectory(fi.DirectoryName);
                }

                // Create an XmlTextWriter using a FileStream.
                fs = new FileStream(_syncFileName, FileMode.Create);
                writer = new XmlTextWriter(fs, new UTF8Encoding());

                // Serialize using the XmlTextWriter.
                serializer.Serialize(writer, _syncConfig);

                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceInfo, String.Format(CultureInfo.InvariantCulture, "Info: configuration file: {0},  was written to sucessfully.", _syncFileName));
            }
            catch (ArgumentOutOfRangeException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: FileMode invalid for the configuration file: {0}", _syncFileName));

                completed = false;
            }
            catch (ArgumentNullException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: The configuration file was null.");

                completed = false;
            }
            catch (ArgumentException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file name: {0} was invalid.}", _syncFileName));

                completed = false;
            }
            catch (SecurityException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The user doesn't hsve the required permissions of open the configuration file: {0}", _syncFileName));

                completed = false;
            }
            catch (UnauthorizedAccessException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: Access to the configuration file: {0} was denied.", _syncFileName));

                completed = false;
            }
            catch (PathTooLongException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0} path is too long {1}", _syncFileName, _syncFileName.Length));

                completed = false;
            }
            catch (NotSupportedException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: There is a colon in the path name");

                completed = false;
            }
            catch (FileNotFoundException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0},  was not found.", _syncFileName));

                completed = false;
            }
            catch (DirectoryNotFoundException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file directory: {0},  was not found.", _syncFileName));

                completed = false;
            }
            catch (InvalidOperationException ex)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An InvalidOpertionException occurred reading the configuration file: {0},  Expection: {1}", _syncFileName, ex.Message));

                completed = false;
            }
            catch (IOException)
            {
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An I/O error occurred in the configuration file: {0}", _syncFileName));

                completed = false;
            }
            finally
            {
                if (writer != null)
                    writer.Close();

                if (fs != null)
                    fs.Close();
            }

            return completed;

        }

        private bool XMLSchemaVersionMatches
        {
            get
            {
                FileStream fs = null;
                XmlReader reader = null;
                string xmlVersion = String.Empty;
                bool readValue = false;

                try
                {
                    fs = new FileStream(_syncFileName, FileMode.Open);
                    reader = new XmlTextReader(fs);
                    reader.MoveToContent();
                    while (reader.Read())
                    {
                        if (readValue)
                        {
                            xmlVersion = reader.Value;
                            break;
                        }
                        if (reader.LocalName == "SchemaVersion")
                        {
                            readValue = true;
                        }

                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: FileMode invalid for the configuration file: {0}", _syncFileName));

                    return false;
                }
                catch (ArgumentNullException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: The configuration file was null.");

                    return false;
                }
                catch (ArgumentException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file name: {0} was invalid.}", _syncFileName));

                    return false;
                }
                catch (SecurityException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The user doesn't hsve the required permissions of open the configuration file: {0}", _syncFileName));

                    return false;
                }
                catch (UnauthorizedAccessException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: Access to the configuration file: {0} was denied.", _syncFileName));

                    return false;
                }
                catch (PathTooLongException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0} path is too long {1}", _syncFileName, _syncFileName.Length));

                    return false;
                }
                catch (NotSupportedException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, "Error: There is a colon in the path name");

                    return false;
                }
                catch (FileNotFoundException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file: {0},  was not found.", _syncFileName));

                    return false;
                }
                catch (DirectoryNotFoundException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: The configuration file directory: {0},  was not found.", _syncFileName));

                    return false;
                }
                catch (InvalidOperationException ex)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An InvalidOpertionException occurred reading the configuration file: {0},  Expection: {1}", _syncFileName, ex.Message));

                    return false;
                }
                catch (IOException)
                {
                    if (_tracing != null)
                        _tracing.WriteTrace(_tracing.MainSwitch.TraceError, String.Format(CultureInfo.InvariantCulture, "Error: An I/O error occurred in the configuration file: {0}", _syncFileName));

                    return false;
                }
                finally
                {
                    if (reader != null)
                        reader.Close();

                    if (fs != null)
                        fs.Close();
                }

                if (xmlVersion == SyncConfigLibraryVersion)
                    return true;
                else
                    return false;
            }
        }


        private string SyncConfigLibraryVersion
        {
            get
            {
                Assembly epmAssembly = Assembly.GetExecutingAssembly();
                System.Reflection.AssemblyName epmAssemblyName = epmAssembly.GetName();
                if (_tracing != null)
                    _tracing.WriteTrace(_tracing.MainSwitch.TraceInfo, String.Format(CultureInfo.InvariantCulture, "Info: Assembly Tested: {0}, Version: {1}", epmAssembly.Location, epmAssemblyName.Version.ToString()));
                return epmAssemblyName.Version.ToString();
            }
        }

        #endregion

    }
}
